////////////////////////////////////////////////////////////////////////////////
/// @file    lcd.c
/// @author  AE TEAM
/// @brief   THIS FILE PROVIDES ALL THE SYSTEM FUNCTIONS.
////////////////////////////////////////////////////////////////////////////////
/// @attention
///
/// THE EXISTING FIRMWARE IS ONLY FOR REFERENCE, WHICH IS DESIGNED TO PROVIDE
/// CUSTOMERS WITH CODING INFORMATION ABOUT THEIR PRODUCTS SO THEY CAN SAVE
/// TIME. THEREFORE, MINDMOTION SHALL NOT BE LIABLE FOR ANY DIRECT, INDIRECT OR
/// CONSEQUENTIAL DAMAGES ABOUT ANY CLAIMS ARISING OUT OF THE CONTENT OF SUCH
/// HARDWARE AND/OR THE USE OF THE CODING INFORMATION CONTAINED HEREIN IN
/// CONNECTION WITH PRODUCTS MADE BY CUSTOMERS.
///
/// <H2><CENTER>&COPY; COPYRIGHT MINDMOTION </CENTER></H2>
////////////////////////////////////////////////////////////////////////////////

// Define to prevent recursive inclusion
#define _LCD_C_

// Files includes
#include "stdlib.h"
#include "hal_conf.h"
#include "hal_device.h"
#include "delay.h"
#include "lcd.h"
#include "font.h"
#include "hal_fsmc.h"
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup MM32_Example_Layer
/// @{

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup LCD
/// @{

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup LCD_Exported_Constants
/// @{

////////////////////////////////////////////////////////////////////////////////
/// @brief  delay
/// @param  nCount:delay time
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
static void ILI9341_Delay ( __IO uint32_t nCount )
{
    for ( ; nCount != 0; nCount -- );
}

u16 POINT_COLOR = 0x0000;
u16 BACK_COLOR = 0xFFFF;

_lcd_dev lcddev;

////////////////////////////////////////////////////////////////////////////////
/// @brief  write reg to LCD
/// @param  regval: The reg to be written
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void LCD_WR_REG(u16 regval)
{

    *(vu16*)(0x60000000) = regval;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  write data to LCD
/// @param  data: The data to be written
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void LCD_WR_DATA(u16 data)
{

    *(vu16*)(0x60000000 | (0x01 << 19)) = data;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  read data to LCD
/// @param  regval: The data to be written
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
u16 LCD_RD_DATA(void)
{
    vu16 ram;
    ram = *(vu16*)(0x60000000 | (0x01 << 19));
    return ram;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  write REG
/// @param  LCD_Reg,LCD_RegValue : The data to be written:
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void LCD_WriteReg(u16 LCD_Reg, u16 LCD_RegValue)
{

    LCD_WR_REG(LCD_Reg);
    LCD_WR_DATA(LCD_RegValue);

}
////////////////////////////////////////////////////////////////////////////////
/// @brief  read reg to LCD
/// @param  LCD_Reg: The data to be read
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
u16 LCD_ReadReg(u16 LCD_Reg)
{
    LCD_WR_REG(LCD_Reg);
    ILI9341_Delay(5);
    return LCD_RD_DATA();
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  Prepare for writting RAM
/// @param  None
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void LCD_WriteRAM_Prepare(void)
{
    *(vu16*)(0x60000000) = lcddev.wramcmd;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  write RAM
/// @param  RGB_Code: RGB value
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void LCD_WriteRAM(u16 RGB_Code)
{
    *(vu16*)(0x60000000 | (0x01 << 19)) = RGB_Code;
}


////////////////////////////////////////////////////////////////////////////////
/// @brief  set BGR and RGB
/// @param  c: color
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
u16 LCD_BGR2RGB(u16 c)
{
    u16  r, g, b, rgb;
    b = (c >> 0) & 0x1f;
    g = (c >> 5) & 0x3f;
    r = (c >> 11) & 0x1f;
    rgb = (b << 11) + (g << 5) + (r << 0);
    return(rgb);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  opt_delay
/// @param  i: The delay time
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void opt_delay(u8 i)
{
    while(i--);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  read point
/// @param  x,y: the informatin about point
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
u16 LCD_ReadPoint(u16 x, u16 y)
{
    u16 r = 0, g = 0, b = 0;
    if(x >= lcddev.width || y >= lcddev.height)return 0;
    LCD_SetCursor(x, y);
    if(lcddev.id == 0X9341 || lcddev.id == 0X6804 || lcddev.id == 0X5310 || lcddev.id == 0X1963)LCD_WR_REG(0X2E); //9341/6804/3510/1963
    else if(lcddev.id == 0X5510)LCD_WR_REG(0X2E00); //5510
    else LCD_WR_REG(0X22);
    if(lcddev.id == 0X9320)opt_delay(2);
    r = LCD_RD_DATA();                              //dummy Read
    if(lcddev.id == 0X1963)return r;
    opt_delay(2);
    r = LCD_RD_DATA();
    if(lcddev.id == 0X9341 || lcddev.id == 0X5310 || lcddev.id == 0X5510) { //9341/NT35310/NT35510
        opt_delay(2);
        b = LCD_RD_DATA();
        g = r & 0XFF;   // 9341/5310/5510,
        g <<= 8;
    }
    if(lcddev.id == 0X9325 || lcddev.id == 0X4535 || lcddev.id == 0X4531 || lcddev.id == 0XB505 || lcddev.id == 0XC505)return r;
    else if(lcddev.id == 0X9341 || lcddev.id == 0X5310 || lcddev.id == 0X5510)return (((r >> 11) << 11) | ((g >> 10) << 5) | (b >> 11)); //ILI9341/NT35310/NT35510
    else return LCD_BGR2RGB(r);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  turn on display
/// @param  None
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void LCD_DisplayOn(void)
{
    if(lcddev.id == 0X9341 || lcddev.id == 0X6804 || lcddev.id == 0X5310 || lcddev.id == 0X1963)LCD_WR_REG(0X29);
    else if(lcddev.id == 0X5510)LCD_WR_REG(0X2900);
    else LCD_WriteReg(0X07, 0x0173);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  turn off display
/// @param  None
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void LCD_DisplayOff(void)
{
    if(lcddev.id == 0X9341 || lcddev.id == 0X6804 || lcddev.id == 0X5310 || lcddev.id == 0X1963)LCD_WR_REG(0X28);
    else if(lcddev.id == 0X5510)LCD_WR_REG(0X2800);
    else LCD_WriteReg(0X07, 0x0);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  set cursor
/// @param  Xpos,Ypos:the information about cursor
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void LCD_SetCursor(u16 Xpos, u16 Ypos)
{
    if(lcddev.id == 0X9341 || lcddev.id == 0X5310) {
        LCD_WR_REG(lcddev.setxcmd);
        LCD_WR_DATA(Xpos >> 8);
        LCD_WR_DATA(Xpos & 0XFF);
        LCD_WR_REG(lcddev.setycmd);
        LCD_WR_DATA(Ypos >> 8);
        LCD_WR_DATA(Ypos & 0XFF);
    }
    else if(lcddev.id == 0X6804) {
        if(lcddev.dir == 1)Xpos = lcddev.width - 1 - Xpos;
        LCD_WR_REG(lcddev.setxcmd);
        LCD_WR_DATA(Xpos >> 8);
        LCD_WR_DATA(Xpos & 0XFF);
        LCD_WR_REG(lcddev.setycmd);
        LCD_WR_DATA(Ypos >> 8);
        LCD_WR_DATA(Ypos & 0XFF);
    }
    else if(lcddev.id == 0X1963) {
        if(lcddev.dir == 0) {
            Xpos = lcddev.width - 1 - Xpos;
            LCD_WR_REG(lcddev.setxcmd);
            LCD_WR_DATA(0);
            LCD_WR_DATA(0);
            LCD_WR_DATA(Xpos >> 8);
            LCD_WR_DATA(Xpos & 0XFF);
        }
        else {
            LCD_WR_REG(lcddev.setxcmd);
            LCD_WR_DATA(Xpos >> 8);
            LCD_WR_DATA(Xpos & 0XFF);
            LCD_WR_DATA((lcddev.width - 1) >> 8);
            LCD_WR_DATA((lcddev.width - 1) & 0XFF);
        }
        LCD_WR_REG(lcddev.setycmd);
        LCD_WR_DATA(Ypos >> 8);
        LCD_WR_DATA(Ypos & 0XFF);
        LCD_WR_DATA((lcddev.height - 1) >> 8);
        LCD_WR_DATA((lcddev.height - 1) & 0XFF);

    }
    else if(lcddev.id == 0X5510) {
        LCD_WR_REG(lcddev.setxcmd);
        LCD_WR_DATA(Xpos >> 8);
        LCD_WR_REG(lcddev.setxcmd + 1);
        LCD_WR_DATA(Xpos & 0XFF);
        LCD_WR_REG(lcddev.setycmd);
        LCD_WR_DATA(Ypos >> 8);
        LCD_WR_REG(lcddev.setycmd + 1);
        LCD_WR_DATA(Ypos & 0XFF);
    }
    else {
        if(lcddev.dir == 1)Xpos = lcddev.width - 1 - Xpos;
        LCD_WriteReg(lcddev.setxcmd, Xpos);
        LCD_WriteReg(lcddev.setycmd, Ypos);
    }
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  LCD scan direction
/// @param  dir
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void LCD_Scan_Dir(u8 dir)
{
    u16 regval = 0;
    u16 dirreg = 0;
    u16 temp;
    if((lcddev.dir == 1 && lcddev.id != 0X6804 && lcddev.id != 0X1963) || (lcddev.dir == 0 && lcddev.id == 0X1963)) {
        switch(dir) {
            case 0:
                dir = 6;
                break;
            case 1:
                dir = 7;
                break;
            case 2:
                dir = 4;
                break;
            case 3:
                dir = 5;
                break;
            case 4:
                dir = 1;
                break;
            case 5:
                dir = 0;
                break;
            case 6:
                dir = 3;
                break;
            case 7:
                dir = 2;
                break;
        }
    }
    if(lcddev.id == 0x9341 || lcddev.id == 0X6804 || lcddev.id == 0X5310 || lcddev.id == 0X5510 || lcddev.id == 0X1963) { //9341/6804/5310/5510/1963,���⴦��
        switch(dir) {
            case L2R_U2D:
                regval |= (0 << 7) | (0 << 6) | (0 << 5);
                break;
            case L2R_D2U:
                regval |= (1 << 7) | (0 << 6) | (0 << 5);
                break;
            case R2L_U2D:
                regval |= (0 << 7) | (1 << 6) | (0 << 5);
                break;
            case R2L_D2U:
                regval |= (1 << 7) | (1 << 6) | (0 << 5);
                break;
            case U2D_L2R:
                regval |= (0 << 7) | (0 << 6) | (1 << 5);
                break;
            case U2D_R2L:
                regval |= (0 << 7) | (1 << 6) | (1 << 5);
                break;
            case D2U_L2R:
                regval |= (1 << 7) | (0 << 6) | (1 << 5);
                break;
            case D2U_R2L:
                regval |= (1 << 7) | (1 << 6) | (1 << 5);
                break;
        }
        if(lcddev.id == 0X5510)dirreg = 0X3600;
        else dirreg = 0X36;
        if((lcddev.id != 0X5310) && (lcddev.id != 0X5510) && (lcddev.id != 0X1963))regval |= 0X08; //5310/5510/1963
        if(lcddev.id == 0X6804)regval |= 0x02;
        LCD_WriteReg(dirreg, regval);
        if(lcddev.id != 0X1963) { //1963
            if(regval & 0X20) {
                if(lcddev.width < lcddev.height) {
                    temp = lcddev.width;
                    lcddev.width = lcddev.height;
                    lcddev.height = temp;
                }
            }
            else {
                if(lcddev.width > lcddev.height) {
                    temp = lcddev.width;
                    lcddev.width = lcddev.height;
                    lcddev.height = temp;
                }
            }
        }
        if(lcddev.id == 0X5510) {
            LCD_WR_REG(lcddev.setxcmd);
            LCD_WR_DATA(0);
            LCD_WR_REG(lcddev.setxcmd + 1);
            LCD_WR_DATA(0);
            LCD_WR_REG(lcddev.setxcmd + 2);
            LCD_WR_DATA((lcddev.width - 1) >> 8);
            LCD_WR_REG(lcddev.setxcmd + 3);
            LCD_WR_DATA((lcddev.width - 1) & 0XFF);
            LCD_WR_REG(lcddev.setycmd);
            LCD_WR_DATA(0);
            LCD_WR_REG(lcddev.setycmd + 1);
            LCD_WR_DATA(0);
            LCD_WR_REG(lcddev.setycmd + 2);
            LCD_WR_DATA((lcddev.height - 1) >> 8);
            LCD_WR_REG(lcddev.setycmd + 3);
            LCD_WR_DATA((lcddev.height - 1) & 0XFF);
        }
        else {
            LCD_WR_REG(lcddev.setxcmd);
            LCD_WR_DATA(0);
            LCD_WR_DATA(0);
            LCD_WR_DATA((lcddev.width - 1) >> 8);
            LCD_WR_DATA((lcddev.width - 1) & 0XFF);
            LCD_WR_REG(lcddev.setycmd);
            LCD_WR_DATA(0);
            LCD_WR_DATA(0);
            LCD_WR_DATA((lcddev.height - 1) >> 8);
            LCD_WR_DATA((lcddev.height - 1) & 0XFF);
        }
    }
    else {
        switch(dir) {
            case L2R_U2D:
                regval |= (1 << 5) | (1 << 4) | (0 << 3);
                break;
            case L2R_D2U:
                regval |= (0 << 5) | (1 << 4) | (0 << 3);
                break;
            case R2L_U2D:
                regval |= (1 << 5) | (0 << 4) | (0 << 3);
                break;
            case R2L_D2U:
                regval |= (0 << 5) | (0 << 4) | (0 << 3);
                break;
            case U2D_L2R:
                regval |= (1 << 5) | (1 << 4) | (1 << 3);
                break;
            case U2D_R2L:
                regval |= (1 << 5) | (0 << 4) | (1 << 3);
                break;
            case D2U_L2R:
                regval |= (0 << 5) | (1 << 4) | (1 << 3);
                break;
            case D2U_R2L:
                regval |= (0 << 5) | (0 << 4) | (1 << 3);
                break;
        }
        dirreg = 0X03;
        regval |= 1 << 12;
        LCD_WriteReg(dirreg, regval);
    }
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  draw point
/// @param  x,y :the information about point
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void LCD_DrawPoint(u16 x, u16 y)
{
    LCD_SetCursor(x, y);
    LCD_WriteRAM_Prepare();
    //LCD->LCD_RAM=POINT_COLOR;
    LCD_WR_DATA(POINT_COLOR);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  draw point
/// @param  x,y,color:the information about point
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void LCD_Fast_DrawPoint(u16 x, u16 y, u16 color)
{
    if(lcddev.id == 0X9341 || lcddev.id == 0X5310) {
        LCD_WR_REG(lcddev.setxcmd);
        LCD_WR_DATA(x >> 8);
        LCD_WR_DATA(x & 0XFF);
        LCD_WR_REG(lcddev.setycmd);
        LCD_WR_DATA(y >> 8);
        LCD_WR_DATA(y & 0XFF);
    }
    else if(lcddev.id == 0X5510) {
        LCD_WR_REG(lcddev.setxcmd);
        LCD_WR_DATA(x >> 8);
        LCD_WR_REG(lcddev.setxcmd + 1);
        LCD_WR_DATA(x & 0XFF);
        LCD_WR_REG(lcddev.setycmd);
        LCD_WR_DATA(y >> 8);
        LCD_WR_REG(lcddev.setycmd + 1);
        LCD_WR_DATA(y & 0XFF);
    }
    else if(lcddev.id == 0X1963) {
        if(lcddev.dir == 0)x = lcddev.width - 1 - x;
        LCD_WR_REG(lcddev.setxcmd);
        LCD_WR_DATA(x >> 8);
        LCD_WR_DATA(x & 0XFF);
        LCD_WR_DATA(x >> 8);
        LCD_WR_DATA(x & 0XFF);
        LCD_WR_REG(lcddev.setycmd);
        LCD_WR_DATA(y >> 8);
        LCD_WR_DATA(y & 0XFF);
        LCD_WR_DATA(y >> 8);
        LCD_WR_DATA(y & 0XFF);
    }
    else if(lcddev.id == 0X6804) {
        if(lcddev.dir == 1)x = lcddev.width - 1 - x;
        LCD_WR_REG(lcddev.setxcmd);
        LCD_WR_DATA(x >> 8);
        LCD_WR_DATA(x & 0XFF);
        LCD_WR_REG(lcddev.setycmd);
        LCD_WR_DATA(y >> 8);
        LCD_WR_DATA(y & 0XFF);
    }
    else {
        if(lcddev.dir == 1)x = lcddev.width - 1 - x;
        LCD_WriteReg(lcddev.setxcmd, x);
        LCD_WriteReg(lcddev.setycmd, y);
    }
    //LCD->LCD_REG=lcddev.wramcmd;
    LCD_WR_REG(lcddev.wramcmd);
    //LCD->LCD_RAM=color;
    LCD_WR_DATA(color);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  LCD background Settings
/// @param  pwm
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void LCD_SSD_BackLightSet(u8 pwm)
{
    LCD_WR_REG(0xBE);
    LCD_WR_DATA(0x05);
    LCD_WR_DATA((u16)(pwm * 2.55));
    LCD_WR_DATA(0x01);
    LCD_WR_DATA(0xFF);
    LCD_WR_DATA(0x00);
    LCD_WR_DATA(0x00);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  LCD display
/// @param  dir :Display direction of LCD
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void LCD_Display_Dir(u8 dir)
{
    if(dir == 0) {
        lcddev.dir = 0;
        lcddev.width = 240;
        lcddev.height = 320;
        if(lcddev.id == 0X9341 || lcddev.id == 0X6804 || lcddev.id == 0X5310) {
            lcddev.wramcmd = 0X2C;
            lcddev.setxcmd = 0X2A;
            lcddev.setycmd = 0X2B;
            if(lcddev.id == 0X6804 || lcddev.id == 0X5310) {
                lcddev.width = 320;
                lcddev.height = 480;
            }
        }
        else if(lcddev.id == 0x5510) {
            lcddev.wramcmd = 0X2C00;
            lcddev.setxcmd = 0X2A00;
            lcddev.setycmd = 0X2B00;
            lcddev.width = 480;
            lcddev.height = 800;
        }
        else if(lcddev.id == 0X1963) {
            lcddev.wramcmd = 0X2C;
            lcddev.setxcmd = 0X2B;
            lcddev.setycmd = 0X2A;
            lcddev.width = 480;
            lcddev.height = 800;
        }
        else {
            lcddev.wramcmd = 0X22;
            lcddev.setxcmd = 0X20;
            lcddev.setycmd = 0X21;
        }
    }
    else {
        lcddev.dir = 1;
        lcddev.width = 320;
        lcddev.height = 240;
        if(lcddev.id == 0X9341 || lcddev.id == 0X5310) {
            lcddev.wramcmd = 0X2C;
            lcddev.setxcmd = 0X2A;
            lcddev.setycmd = 0X2B;
        }
        else if(lcddev.id == 0X6804) {
            lcddev.wramcmd = 0X2C;
            lcddev.setxcmd = 0X2B;
            lcddev.setycmd = 0X2A;
        }
        else if(lcddev.id == 0x5510) {
            lcddev.wramcmd = 0X2C00;
            lcddev.setxcmd = 0X2A00;
            lcddev.setycmd = 0X2B00;
            lcddev.width = 800;
            lcddev.height = 480;
        }
        else if(lcddev.id == 0X1963) {
            lcddev.wramcmd = 0X2C;
            lcddev.setxcmd = 0X2A;
            lcddev.setycmd = 0X2B;
            lcddev.width = 800;
            lcddev.height = 480;
        }
        else {
            lcddev.wramcmd = 0X22;
            lcddev.setxcmd = 0X21;
            lcddev.setycmd = 0X20;
        }
        if(lcddev.id == 0X6804 || lcddev.id == 0X5310) {
            lcddev.width = 480;
            lcddev.height = 320;
        }
    }
    LCD_Scan_Dir(DFT_SCAN_DIR);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  LCD window configuration
/// @param  sx,sy,width,height:the information about LCD window
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void LCD_Set_Window(u16 sx, u16 sy, u16 width, u16 height)
{
    u8 hsareg, heareg, vsareg, veareg;
    u16 hsaval, heaval, vsaval, veaval;
    u16 twidth, theight;
    twidth = sx + width - 1;
    theight = sy + height - 1;
    if(lcddev.id == 0X9341 || lcddev.id == 0X5310 || lcddev.id == 0X6804 || (lcddev.dir == 1 && lcddev.id == 0X1963)) {
        LCD_WR_REG(lcddev.setxcmd);
        LCD_WR_DATA(sx >> 8);
        LCD_WR_DATA(sx & 0XFF);
        LCD_WR_DATA(twidth >> 8);
        LCD_WR_DATA(twidth & 0XFF);
        LCD_WR_REG(lcddev.setycmd);
        LCD_WR_DATA(sy >> 8);
        LCD_WR_DATA(sy & 0XFF);
        LCD_WR_DATA(theight >> 8);
        LCD_WR_DATA(theight & 0XFF);
    }
    else if(lcddev.id == 0X1963) {
        sx = lcddev.width - width - sx;
        height = sy + height - 1;
        LCD_WR_REG(lcddev.setxcmd);
        LCD_WR_DATA(sx >> 8);
        LCD_WR_DATA(sx & 0XFF);
        LCD_WR_DATA((sx + width - 1) >> 8);
        LCD_WR_DATA((sx + width - 1) & 0XFF);
        LCD_WR_REG(lcddev.setycmd);
        LCD_WR_DATA(sy >> 8);
        LCD_WR_DATA(sy & 0XFF);
        LCD_WR_DATA(height >> 8);
        LCD_WR_DATA(height & 0XFF);
    }
    else if(lcddev.id == 0X5510) {
        LCD_WR_REG(lcddev.setxcmd);
        LCD_WR_DATA(sx >> 8);
        LCD_WR_REG(lcddev.setxcmd + 1);
        LCD_WR_DATA(sx & 0XFF);
        LCD_WR_REG(lcddev.setxcmd + 2);
        LCD_WR_DATA(twidth >> 8);
        LCD_WR_REG(lcddev.setxcmd + 3);
        LCD_WR_DATA(twidth & 0XFF);
        LCD_WR_REG(lcddev.setycmd);
        LCD_WR_DATA(sy >> 8);
        LCD_WR_REG(lcddev.setycmd + 1);
        LCD_WR_DATA(sy & 0XFF);
        LCD_WR_REG(lcddev.setycmd + 2);
        LCD_WR_DATA(theight >> 8);
        LCD_WR_REG(lcddev.setycmd + 3);
        LCD_WR_DATA(theight & 0XFF);
    }
    else {
        if(lcddev.dir == 1) {

            hsaval = sy;
            heaval = theight;
            vsaval = lcddev.width - twidth - 1;
            veaval = lcddev.width - sx - 1;
        }
        else {
            hsaval = sx;
            heaval = twidth;
            vsaval = sy;
            veaval = theight;
        }
        hsareg = 0X50;
        heareg = 0X51;
        vsareg = 0X52;
        veareg = 0X53;

        LCD_WriteReg(hsareg, hsaval);
        LCD_WriteReg(heareg, heaval);
        LCD_WriteReg(vsareg, vsaval);
        LCD_WriteReg(veareg, veaval);
        LCD_SetCursor(sx, sy);
    }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  Initialize LCD
/// @param  None
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void LCD_Init(void)
{

    lcddev.id = LCD_ReadReg(0x0000);
    DELAY_Ms(50);
    lcddev.id = 0x9341;

    if(lcddev.id == 0X9341) {
        LCD_WR_REG(0xCF);
        LCD_WR_DATA(0x00);
        LCD_WR_DATA(0xC1);
        LCD_WR_DATA(0X30);
        LCD_WR_REG(0xED);
        LCD_WR_DATA(0x64);
        LCD_WR_DATA(0x03);
        LCD_WR_DATA(0X12);
        LCD_WR_DATA(0X81);
        LCD_WR_REG(0xE8);
        LCD_WR_DATA(0x85);
        LCD_WR_DATA(0x10);
        LCD_WR_DATA(0x7A);
        LCD_WR_REG(0xCB);
        LCD_WR_DATA(0x39);
        LCD_WR_DATA(0x2C);
        LCD_WR_DATA(0x00);
        LCD_WR_DATA(0x34);
        LCD_WR_DATA(0x02);
        LCD_WR_REG(0xF7);
        LCD_WR_DATA(0x20);
        LCD_WR_REG(0xEA);
        LCD_WR_DATA(0x00);
        LCD_WR_DATA(0x00);
        LCD_WR_REG(0xC0);    //Power control
        LCD_WR_DATA(0x1B);   //VRH[5:0]
        LCD_WR_REG(0xC1);    //Power control
        LCD_WR_DATA(0x01);   //SAP[2:0];BT[3:0]
        LCD_WR_REG(0xC5);    //VCM control
        LCD_WR_DATA(0x30);   //3F
        LCD_WR_DATA(0x30);   //3C
        LCD_WR_REG(0xC7);    //VCM control2
        LCD_WR_DATA(0XB7);
        LCD_WR_REG(0x36);    // Memory Access Control
        LCD_WR_DATA(0x48);
        LCD_WR_REG(0x3A);
        LCD_WR_DATA(0x55);
        LCD_WR_REG(0xB1);
        LCD_WR_DATA(0x00);
        LCD_WR_DATA(0x1A);
        LCD_WR_REG(0xB6);    // Display Function Control
        LCD_WR_DATA(0x0A);
        LCD_WR_DATA(0xA2);
        LCD_WR_REG(0xF2);    // 3Gamma Function Disable
        LCD_WR_DATA(0x00);
        LCD_WR_REG(0x26);    //Gamma curve selected
        LCD_WR_DATA(0x01);
        LCD_WR_REG(0xE0);    //Set Gamma
        LCD_WR_DATA(0x0F);
        LCD_WR_DATA(0x2A);
        LCD_WR_DATA(0x28);
        LCD_WR_DATA(0x08);
        LCD_WR_DATA(0x0E);
        LCD_WR_DATA(0x08);
        LCD_WR_DATA(0x54);
        LCD_WR_DATA(0XA9);
        LCD_WR_DATA(0x43);
        LCD_WR_DATA(0x0A);
        LCD_WR_DATA(0x0F);
        LCD_WR_DATA(0x00);
        LCD_WR_DATA(0x00);
        LCD_WR_DATA(0x00);
        LCD_WR_DATA(0x00);
        LCD_WR_REG(0XE1);    //Set Gamma
        LCD_WR_DATA(0x00);
        LCD_WR_DATA(0x15);
        LCD_WR_DATA(0x17);
        LCD_WR_DATA(0x07);
        LCD_WR_DATA(0x11);
        LCD_WR_DATA(0x06);
        LCD_WR_DATA(0x2B);
        LCD_WR_DATA(0x56);
        LCD_WR_DATA(0x3C);
        LCD_WR_DATA(0x05);
        LCD_WR_DATA(0x10);
        LCD_WR_DATA(0x0F);
        LCD_WR_DATA(0x3F);
        LCD_WR_DATA(0x3F);
        LCD_WR_DATA(0x0F);
        LCD_WR_REG(0x2B);
        LCD_WR_DATA(0x00);
        LCD_WR_DATA(0x00);
        LCD_WR_DATA(0x01);
        LCD_WR_DATA(0x3f);
        LCD_WR_REG(0x2A);
        LCD_WR_DATA(0x00);
        LCD_WR_DATA(0x00);
        LCD_WR_DATA(0x00);
        LCD_WR_DATA(0xef);
        LCD_WR_REG(0x11); //Exit Sleep
        DELAY_Ms(120);
        LCD_WR_REG(0x29); //display on
    }
    LCD_Display_Dir(0);
    //LCD_LED=1;
    GPIO_SetBits(GPIOC, GPIO_Pin_10);
    LCD_Clear(WHITE);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  Set LCD enter Sleep mode
/// @param  None
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void LCD_Enter_Sleep_ILI9341(void)
{
    LCD_WR_REG(0x28); // Display off
    LCD_WR_REG(0x10); // Enter Sleep mode
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  Set LCD exit Sleep mode
/// @param  None
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void LCD_Exit_Sleep_ILI9341(void)
{
    LCD_WR_REG(0x11); // Exit Sleep
    DELAY_Ms(120);
    LCD_WR_REG(0x29); // Display on
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  Clear LCD screen
/// @param  color
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void LCD_Clear(u16 color)
{
    u32 index = 0;
    u32 totalpoint = lcddev.width;
    totalpoint *= lcddev.height;
    if((lcddev.id == 0X6804) && (lcddev.dir == 1)) {
        lcddev.dir = 0;
        lcddev.setxcmd = 0X2A;
        lcddev.setycmd = 0X2B;
        LCD_SetCursor(0x00, 0x0000);
        lcddev.dir = 1;
        lcddev.setxcmd = 0X2B;
        lcddev.setycmd = 0X2A;
    }
    else LCD_SetCursor(0x00, 0x0000);
    LCD_WriteRAM_Prepare();
    for(index = 0; index < totalpoint; index++) {
        //LCD->LCD_RAM=color;
        //LCD_WR_DATA(color);
        *(vu16*)(0x60000000 | (0x01 << 19)) = color;
    }
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  LCD fill
/// @param  sx,sy,ex,ey,*color :the informatin about fill color and area
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void LCD_Fill(u16 sx, u16 sy, u16 ex, u16 ey, u16 color)
{
    u16 i, j;
    u16 xlen = 0;
    u16 temp;
    if((lcddev.id == 0X6804) && (lcddev.dir == 1)) {
        temp = sx;
        sx = sy;
        sy = lcddev.width - ex - 1;
        ex = ey;
        ey = lcddev.width - temp - 1;
        lcddev.dir = 0;
        lcddev.setxcmd = 0X2A;
        lcddev.setycmd = 0X2B;
        LCD_Fill(sx, sy, ex, ey, color);
        lcddev.dir = 1;
        lcddev.setxcmd = 0X2B;
        lcddev.setycmd = 0X2A;
    }
    else {
        xlen = ex - sx + 1;
        for(i = sy; i <= ey; i++) {
            LCD_SetCursor(sx, i);
            LCD_WriteRAM_Prepare();
            for(j = 0; j < xlen; j++)
                // LCD->LCD_RAM=color;
                LCD_WR_DATA(color);
        }
    }
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  fill color
/// @param  sx,sy,ex,ey,*color :the informatin about fill color and area
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void LCD_Color_Fill(u16 sx, u16 sy, u16 ex, u16 ey, u16* color)
{
    u16 height, width;
    u16 i, j;
    width = ex - sx + 1;
    height = ey - sy + 1;
    for(i = 0; i < height; i++) {
        LCD_SetCursor(sx, sy + i);
        LCD_WriteRAM_Prepare();
        for(j = 0; j < width; j++)
            //LCD->LCD_RAM=color[i*width+j];
            LCD_WR_DATA(color[i * width + j]);/////
    }
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  draw line
/// @param  x,y:the information about line
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void LCD_DrawLine(u16 x1, u16 y1, u16 x2, u16 y2)
{
    u16 t;
    int xerr = 0, yerr = 0, delta_x, delta_y, distance;
    int incx, incy, uRow, uCol;
    delta_x = x2 - x1;
    delta_y = y2 - y1;
    uRow = x1;
    uCol = y1;
    if(delta_x > 0)incx = 1;
    else if(delta_x == 0)incx = 0;
    else {
        incx = -1;
        delta_x = -delta_x;
    }
    if(delta_y > 0)incy = 1;
    else if(delta_y == 0)incy = 0;
    else {
        incy = -1;
        delta_y = -delta_y;
    }
    if( delta_x > delta_y)distance = delta_x;
    else distance = delta_y;
    for(t = 0; t <= distance + 1; t++ ) {
        LCD_DrawPoint(uRow, uCol);
        xerr += delta_x ;
        yerr += delta_y ;
        if(xerr > distance) {
            xerr -= distance;
            uRow += incx;
        }
        if(yerr > distance) {
            yerr -= distance;
            uCol += incy;
        }
    }
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  draw rectangle
/// @param  x,y:the information about rectangle
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void LCD_DrawRectangle(u16 x1, u16 y1, u16 x2, u16 y2)
{
    LCD_DrawLine(x1, y1, x2, y1);
    LCD_DrawLine(x1, y1, x1, y2);
    LCD_DrawLine(x1, y2, x2, y2);
    LCD_DrawLine(x2, y1, x2, y2);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  draw circle
/// @param  x0,y0,r:the information about circle
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void LCD_Draw_Circle(u16 x0, u16 y0, u8 r)
{
    int a, b;
    int di;
    a = 0;
    b = r;
    di = 3 - (r << 1);
    while(a <= b) {
        LCD_DrawPoint(x0 + a, y0 - b);        //5
        LCD_DrawPoint(x0 + b, y0 - a);        //0
        LCD_DrawPoint(x0 + b, y0 + a);        //4
        LCD_DrawPoint(x0 + a, y0 + b);        //6
        LCD_DrawPoint(x0 - a, y0 + b);        //1
        LCD_DrawPoint(x0 - b, y0 + a);
        LCD_DrawPoint(x0 - a, y0 - b);        //2
        LCD_DrawPoint(x0 - b, y0 - a);        //7
        a++;

        if(di < 0)di += 4 * a + 6;
        else {
            di += 10 + 4 * (a - b);
            b--;
        }
    }
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  display char
/// @param  x,y,num,size,mode: the information about char
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void LCD_ShowChar(u16 x, u16 y, u8 num, u8 size, u8 mode)
{
    u8 temp, t1, t;
    u16 y0 = y;
    u8 csize = (size / 8 + ((size % 8) ? 1 : 0)) * (size / 2);///
    num = num - ' ';
    for(t = 0; t < csize; t++) {
        if(size == 12)temp = asc2_1206[num][t];
        else if(size == 16)temp = asc2_1608[num][t];
        else if(size == 24)temp = asc2_2412[num][t];
        else return;
        for(t1 = 0; t1 < 8; t1++) {
            if(temp & 0x80)LCD_Fast_DrawPoint(x, y, POINT_COLOR);
            else if(mode == 0)LCD_Fast_DrawPoint(x, y, BACK_COLOR);
            temp <<= 1;
            y++;
            if(y >= lcddev.height)return;
            if((y - y0) == size) {
                y = y0;
                x++;
                if(x >= lcddev.width)return;
                break;
            }
        }
    }
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  M to the NTH powert
/// @param  m,n
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
u32 LCD_Pow(u8 m, u8 n)
{
    u32 result = 1;
    while(n--)result *= m;
    return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  display number
/// @param  x,y,num,len,size : the information about number
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void LCD_ShowNum(u16 x, u16 y, u32 num, u8 len, u8 size)
{
    u8 t, temp;
    u8 enshow = 0;
    for(t = 0; t < len; t++) {
        temp = (num / LCD_Pow(10, len - t - 1)) % 10;
        if(enshow == 0 && t < (len - 1)) {
            if(temp == 0) {
                LCD_ShowChar(x + (size / 2)*t, y, ' ', size, 0);
                continue;
            }
            else enshow = 1;

        }
        LCD_ShowChar(x + (size / 2)*t, y, temp + '0', size, 0);
    }
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  display number
/// @param  x,y,num,len,size,mode : the information about number
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void LCD_ShowxNum(u16 x, u16 y, u32 num, u8 len, u8 size, u8 mode)
{
    u8 t, temp;
    u8 enshow = 0;
    for(t = 0; t < len; t++) {
        temp = (num / LCD_Pow(10, len - t - 1)) % 10;
        if(enshow == 0 && t < (len - 1)) {
            if(temp == 0) {
                if(mode & 0X80)LCD_ShowChar(x + (size / 2)*t, y, '0', size, mode & 0X01);
                else LCD_ShowChar(x + (size / 2)*t, y, ' ', size, mode & 0X01);
                continue;
            }
            else enshow = 1;

        }
        LCD_ShowChar(x + (size / 2)*t, y, temp + '0', size, mode & 0X01);
    }
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  display string
/// @param  x,y,width,height,size,*p: the information about string
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void LCD_ShowString(u16 x, u16 y, u16 width, u16 height, u8 size, u8* p)
{
    u8 x0 = x;
    width += x;
    height += y;
    while((*p <= '~') && (*p >= ' ')) {
        if(x >= width) {
            x = x0;
            y += size;
        }
        if(y >= height)break;
        LCD_ShowChar(x, y, *p, size, 0);
        x += size / 2;
        p++;
    }
}

/// @}

/// @}

/// @}
